home *** CD-ROM | disk | FTP | other *** search
/ Shareware Super Platinum 8 / Shareware Super Platinum 8.iso / mac / PROGTOOL / PASSDK30.ZIP;1 / DISK1.ZIP / PAS / PCM / WAVEIT.C < prev    next >
Encoding:
C/C++ Source or Header  |  1992-07-28  |  15.4 KB  |  734 lines

  1. /*$Author:   DCODY  $*/
  2. /*$Date:   28 Jul 1992 14:28:32  $*/
  3. /*$Header:   W:/sccs/pcmapps/waveit.c_v   1.2   28 Jul 1992 14:28:32   DCODY  $*/
  4. /*$Log:   W:/sccs/pcmapps/waveit.c_v  $
  5.  * 
  6.  *    Rev 1.2   28 Jul 1992 14:28:32   DCODY
  7.  * added parameter for 16 pcm specified on the command line.
  8.  * 
  9.  *    Rev 1.1   23 Jun 1992 16:10:28   DCODY
  10.  * No change.
  11.  * 
  12.  *    Rev 1.0   15 Jun 1992 09:26:58   BCRANE
  13.  * Initial revision.
  14. */
  15. /*$Logfile:   W:/sccs/pcmapps/waveit.c_v  $*/
  16. /*$Modtimes$*/
  17. /*$Revision:   1.2  $*/
  18. /*$Workfile:   waveit.c  $*/
  19.  
  20.  
  21.     /*\
  22.     |*|----====< WaveIt.C >====----
  23.     |*|
  24.     |*| Convert a ".VOC" file to a Wave file
  25.     |*|
  26.     |*| Copyright (c) 1991, Media Vision, Inc. All rights reserved.
  27.     |*|
  28.     \*/
  29.  
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <malloc.h>
  33.  
  34. #include "play.h"
  35. #include "common.h"
  36.  
  37.  
  38.     /*\
  39.     |*|----====< Local Variables >====----
  40.     \*/
  41.  
  42.         static FILE *inf;                /* ".VOC" input file            */
  43.         static FILE *ouf;                /* ".WAV" output file           */
  44.  
  45.         VOCHDR         VOCHeader;         /* block header                 */
  46.         bVOCDATA     b1VoiceData;        /* voice daa header             */
  47.         bCONTINUE     b2VoiceData;        /* continuation block header    */
  48.  
  49.         WaveInfo    _WaveHeader = { /* Wave File Header             */
  50.                 1,                        /* format category                */
  51.                 1,                        /* stereo/mono                    */
  52.                 0,                        /* sample rate                    */
  53.                 0,                        /* stereo * sample rate         */
  54.                 1,                        /* block alignment (1=byte)     */
  55.                 8                        /* # byte bits per sample        */
  56.         };
  57.  
  58.         int  SampleRate;                /* Sample data rate             */
  59.         long SampleSize;                /* # of bytes in the sample     */
  60.         long TotalSampleSize = 0;        /* total length of sample data    */
  61.  
  62.         long UserSampleRate = -1;        /* default to prompt operator    */
  63.         int  UserStereoMono = 0;        /* default to mono                */
  64.         int  PCMSize = 8;
  65.  
  66.         char SourceFile[100];            /* source file name storage     */
  67.         char TargetFile[100];            /* target file name storage     */
  68.         int  lastsample;                /* last valid pcm sample        */
  69.  
  70.         static fpos_t  riffpos;
  71.         static fpos_t  datapos;
  72.  
  73.         int  PadByte;
  74.         int  BlockType;
  75.  
  76.         int  FileType;
  77.  
  78.         long GetPlayRate();
  79.         char getkey();
  80.  
  81. #define VOC_FORMAT        0x0001
  82. #define SOU_FORMAT        0x0002
  83.  
  84.  
  85.     /*\
  86.     |*|
  87.     |*|----====< Main >====----
  88.     |*|
  89.     |*| Play the voice file out to the PCM hardware
  90.     |*|
  91.     \*/
  92.  
  93. main(argc,argv)
  94.     int  argc;
  95.     char *argv[];
  96. {
  97.  
  98.     /* set the runtime switches                                         */
  99.  
  100.         CommandLine (argc,argv);
  101.  
  102.     /* get header data from the .VOC file & point to the first block    */
  103.  
  104.         PreProcessFile ();
  105.  
  106.     /* output the wave file data...                                     */
  107.  
  108.         lastsample = GetNextSample();
  109.         while (!feof (inf)) {
  110.             putc (lastsample,ouf);
  111.             lastsample = GetNextSample();
  112.             TotalSampleSize++;
  113.         }
  114.  
  115.         WriteckSize ( );
  116.         fclose        ( ouf );
  117.  
  118.     /* exit to DOS                                                        */
  119.  
  120.         DoExit(0);
  121.  
  122. }
  123.  
  124.     /*\
  125.     |*|----====< CommandLine >====----
  126.     |*|
  127.     |*| process the command line switches
  128.     |*|
  129.     \*/
  130. int CommandLine(argc,argv)
  131.     int argc;
  132.     char *argv[];
  133. {
  134. char *s,c;
  135. int n,temp;
  136. long longtemp;
  137.  
  138.     /* logo...                                                            */
  139.  
  140.         printf ("\nPCM Conversion Utility, version 1.05\n");
  141.         printf ("Courtesy of Media Vision, Inc., Fremont, CA.\n\n");
  142.  
  143.     /* exit if too few parameters                                        */
  144.  
  145.         if (argc < 3) {
  146.  
  147.             printf ("   To Use:  DOS>WAVEIT [FILE.xxx] [FILE.WAV] [Rxxxx] [s] [16]\n\n");
  148.             printf ("   Where:   [FILE.xxx] is a .VOC or other 8 bit PCM input file.\n");
  149.             printf ("            [FILE.WAV] is the .WAV output file.\n");
  150.             printf ("            [Rxxxxx]   specifies a new sample rate.\n");
  151.             printf ("            [S]        specifies stereo instead of mono.\n");
  152.             printf ("            [16]       specifies 16 bit PCM\n\n");
  153.             DoExit (1);
  154.         }
  155.  
  156.     /* attempt to open the users disk file                                */
  157.  
  158.         strcpy (SourceFile,argv[1]);
  159.         if ((inf = fopen(argv[1],"rb")) == 0) {
  160.             printf ("\aBad Input File Name: \"%s\" Try Again!\n",argv[1]);
  161.             DoExit (1);
  162.         }
  163.  
  164.     /* make sure the new target does not exist                            */
  165.  
  166.         if ((ouf = fopen(argv[2],"rb")) != 0) {
  167.             fclose (ouf);
  168.             printf ("\"%s\" already exists. Overwrite? (y/n) ",argv[2]);
  169.             c = getkey();
  170.             if ((c & 0x5f) != 'Y')
  171.                 DoExit (1);
  172.         }
  173.  
  174.     /* attempt to open our work file                                    */
  175.  
  176.         strcpy (TargetFile,argv[2]);
  177.         if ((ouf = fopen(argv[2],"wb")) == 0) {
  178.             printf ("\Bad Output File Name: \"%s\" Try Again!\n");
  179.             DoExit (1);
  180.         }
  181.  
  182.     /* determine if this is a .sou (or any non-.voc file file            */
  183.  
  184.         s = argv[1] - 1;
  185.         while (*++s) {
  186.             if (islower(*s))
  187.                 *s &= 0x5f;
  188.         }
  189.  
  190.         if (strcmp (s-4,".VOC") == 0)
  191.             FileType = VOC_FORMAT;
  192.         else
  193.             FileType = SOU_FORMAT;
  194.  
  195.     /* process the other command line switches                            */
  196.  
  197.         n = 3;
  198.         while (n < argc) {
  199.  
  200.             s = argv[n++];
  201.  
  202.             if (*s == '/') s++;
  203.             if (*s == '-') s++;
  204.  
  205.             switch (*s & 0x5f) {
  206.  
  207.                 case '1' & 0x5f:
  208.                     PCMSize = 16;
  209.                     break;
  210.  
  211.                 case 'R':
  212.                     if (sscanf (++s,"%ld",&longtemp) == 1) {
  213.                         if ((longtemp >4000L) && (longtemp < 88200L))
  214.                             UserSampleRate = longtemp;
  215.                     }
  216.                     break;
  217.  
  218.                 case 'S':
  219.                     UserStereoMono = 1;
  220.                     break;
  221.  
  222.                 default:
  223.                     break;
  224.             }
  225.         }
  226.  
  227. }
  228.  
  229.  
  230.     /*\
  231.     |*|----====< DoExit() >====----
  232.     |*|
  233.     |*| Exit to DOS
  234.     |*|
  235.     \*/
  236. int DoExit(cc)
  237.     int cc;
  238. {
  239.         fclose (ouf);
  240.         exit   (cc);
  241. }
  242.  
  243.     /*\
  244.     |*|----====< GetNextSample >====----
  245.     |*|
  246.     |*| Get the next sample byte
  247.     |*|
  248.     \*/
  249. int GetNextSample()
  250. {
  251. char buff[10],*b;
  252. long *ptr;
  253. int n;
  254.  
  255.         if (FileType == SOU_FORMAT) {
  256.             return (getc(inf));
  257.         }
  258.         else {
  259.  
  260.             /* if data available, just return the next byte             */
  261.  
  262.             if (SampleSize--) {
  263.  
  264.                 switch (BlockType) {
  265.  
  266.                     case VOICECONTINUE:
  267.                     case VOICEDATA:
  268.                         return (getc(inf));
  269.  
  270.                     case SILENCE:
  271.                     default:
  272.                         return (0x80);
  273.                 }
  274.             }
  275.  
  276.         /* process each voice data record                                */
  277.         /* get the next partial header                                    */
  278.  
  279.             b = (char *) &b1VoiceData;
  280.             for (n=0;n<(sizeof(bVOCDATAHDR));n++)
  281.                 *b++ = getc(inf);
  282.  
  283.         /* process the header                                            */
  284.  
  285.             switch (BlockType = (b1VoiceData.btype & 0xff) ) {
  286.  
  287.                 case TERMINATOR:
  288.  
  289.                     /* all done, just quit now. who cares...            */
  290.  
  291.                         WriteckSize();
  292.                         DoExit(0);
  293.  
  294.                 case VOICECONTINUE:
  295.  
  296.                     /* get the size of the data portion                 */
  297.  
  298.                         ptr = (long*) &b1VoiceData.bsize[0];
  299.                         SampleSize = (*ptr & 0x00ffffff);
  300.  
  301.                     /* return the next byte                             */
  302.  
  303.                         SampleSize--;
  304.                         return (getc(inf));
  305.  
  306.                 case VOICEDATA:
  307.  
  308.                     /* fill out the rest of the header                    */
  309.  
  310.                         for (n=0;n<(sizeof(bVOCDATA)-(sizeof(bVOCDATAHDR)));n++)
  311.                              *b++ = getc(inf);
  312.  
  313.                     /* get the size of the data portion                 */
  314.  
  315.                         ptr = (long*) &b1VoiceData.bsize[0];
  316.                         SampleSize = (*ptr & 0x00ffffff) - 2;
  317.  
  318.                     /* return the next byte                             */
  319.  
  320.                         SampleSize--;
  321.                         return (getc(inf));
  322.  
  323.                 case SILENCE:
  324.  
  325.                     /* fill out the rest of the header                    */
  326.  
  327.                         for (n=0;n<(sizeof(bSILENCE)-(sizeof(bVOCDATAHDR)));n++)
  328.                              *b++ = getc(inf);
  329.  
  330.                         SampleSize = LONG (((bSILENCE*)&b1VoiceData)->period);
  331.  
  332.                         SampleSize--;
  333.                         return (0x80);
  334.  
  335.                 case MARKER:
  336.                     printf ("MARKER - Currently an Unsupported header entry!\n");
  337.                     DoExit(0);
  338.  
  339.                 case ASCIITEXT:
  340.                     printf ("ASCIITEXT - Currently an Unsupported header entry!\n");
  341.                     DoExit(0);
  342.  
  343.                 case REPEAT:
  344.                     printf ("REPEAT - Currently an Unsupported header entry!\n");
  345.                     DoExit(0);
  346.  
  347.                 case ENDREPEAT:
  348.                     printf ("ENDREPEAT - Currently an Unsupported header entry!\n");
  349.                     DoExit(0);
  350.  
  351.                 default:
  352.                     printf ("\aUnknown record type encountered in .VOC file!\n");
  353.                     DoExit(0);
  354.             }
  355.         }
  356. }
  357.  
  358.  
  359.     /*\
  360.     |*|----====< getkey >====----
  361.     |*|
  362.     |*| get a key
  363.     |*|
  364.     \*/
  365. char getkey()
  366. {
  367. char c;
  368.  
  369.     while (kbhit()) getch();
  370.     while (!kbhit()) ;
  371.     putch(c = getch());
  372.     putch('\n');
  373.     putch('\r');
  374.     return (c);
  375. }
  376.  
  377.  
  378.     /*\
  379.     |*|----====< GetPlayRate >====----
  380.     |*|
  381.     |*| Get the playing rate of this sample.
  382.     |*|
  383.     \*/
  384. long GetPlayRate(ptr)
  385.     bVOCDATA *ptr;
  386. {
  387. int n;
  388. char c;
  389. char buff[100];
  390.  
  391.     switch (FileType) {
  392.  
  393.         case VOC_FORMAT:
  394.  
  395.             /* get the sample rate                                        */
  396.  
  397.                 if (UserSampleRate != -1)
  398.                     return(UserSampleRate);
  399.  
  400.                 n = ptr->sampler  & 0xff;
  401.  
  402.                 while (1) {
  403.                     if (n == 166)
  404.                         return (11025L);
  405.  
  406.                     if (n == 211)
  407.                         return (22050L);
  408.  
  409.                     printf ("\n.WAV files only accept 11k or 22k from .VOC files. Your .VOC file\n");
  410.                     printf ("indicates this sample to be recorded at %ldkhz. Do you wish to\n",(1000000L/(256-n)));
  411.                     printf ("(A)accept this, or make it (1)11k, (2)22k, (O)other or (Q)quit (A/1/2/O/Q) ");
  412.  
  413.                     c = getkey();
  414.  
  415.                     switch (c) {
  416.  
  417.                         case 'a':
  418.                         case 'A':
  419.                             return ( LONG(1000000L/(256-n)) );
  420.  
  421.                         case '1':
  422.                             return (11025L);
  423.                             break;
  424.  
  425.                         case '2':
  426.                             return (22050L);
  427.                             break;
  428.  
  429.                         case 'O':
  430.                         case 'o':
  431.                             do {
  432.                                 printf ("Enter the new sample rate :");
  433.                                 gets(buff);
  434.                             } while (sscanf (buff,"%ld",&UserSampleRate) != 1);
  435.                             return (UserSampleRate);
  436.  
  437.                         case 'Q':
  438.                         case 'q':
  439.                             DoExit();
  440.  
  441.                         default:;
  442.                     }
  443.                 }
  444.             break;
  445.  
  446.         case SOU_FORMAT:
  447.  
  448.             /* need a sample rate    */
  449.  
  450.                 if (UserSampleRate != -1)
  451.                     return(UserSampleRate);
  452.  
  453.                 printf ("The .SOU file needs a sample rate.\n");
  454.                 printf ("Do you wish to make it (1)11k, (2)22k or (o)other? (1/2/O) ");
  455.  
  456.                 c = getkey();
  457.  
  458.                 switch (c) {
  459.  
  460.                     case 'O':
  461.                     case 'o':
  462.                         do {
  463.                             printf ("Enter the new sample rate :");
  464.                             gets(buff);
  465.                         } while (sscanf (buff,"%ld",&UserSampleRate) != 1);
  466.                         return (UserSampleRate);
  467.  
  468.                     case '1':
  469.                         return (11025L);
  470.  
  471.                     case '2':
  472.                         return (22050L);
  473.  
  474.                     default:;
  475.                 }
  476.  
  477.         default:
  478.             break;
  479.  
  480.         }
  481.  
  482. }
  483.  
  484.  
  485.     /*\
  486.     |*|----====< PreProcessFile >====----
  487.     |*|
  488.     |*| Get the header data & return pointing to the 1st byte in the file
  489.     |*|
  490.     \*/
  491. int PreProcessFile()
  492. {
  493. long *ptr;
  494. int n;
  495. char *b,c;
  496.  
  497.  
  498.         if (FileType == VOC_FORMAT) {
  499.  
  500.             /* rewind the input file to the 1st byte                            */
  501.  
  502.                 fseek(inf,0L,SEEK_SET);
  503.  
  504.             /* get the header of the voice file                                 */
  505.  
  506.                 b = (char *) &VOCHeader;
  507.                 for (n=0;n<(sizeof (VOCHDR));n++)
  508.                     *b++ = getc(inf);
  509.  
  510.                 if (feof(inf)) {
  511.                     printf ("\aUnexpected EOF on input from Voice File\n");
  512.                     DoExit (1);
  513.                 }
  514.  
  515.             /* Make sure it's a legit file                                      */
  516.  
  517.                 if (strncmp (VOCHeader.id,"Creative Voice File",0x13) != 0) {
  518.                     printf ("\aInvalid Header in Voice File\n");
  519.                     DoExit (1);
  520.                 }
  521.  
  522.             /* process the 1st voice data record                                */
  523.             /* bomb out if eof                                                    */
  524.  
  525.                 if (feof(inf)) {
  526.                     printf ("\aUnexpected EOF on input!\n");
  527.                     DoExit(0);
  528.                 }
  529.  
  530.             /* get the next partial header                                        */
  531.  
  532.                 b = (char *) &b1VoiceData;
  533.                 for (n=0;n<(sizeof(bVOCDATAHDR));n++)
  534.                     *b++ = getc(inf);
  535.  
  536.             /* process the header                                                */
  537.  
  538.                 switch (BlockType = (b1VoiceData.btype & 0xff) ) {
  539.  
  540.                     case VOICEDATA:
  541.  
  542.                         /* fill out the rest of the header                        */
  543.  
  544.                             for (n=0;n<(sizeof(bVOCDATA)-(sizeof(bVOCDATAHDR)));n++)
  545.                                  *b++ = getc(inf);
  546.  
  547.                                 _WaveHeader.nSamplesPerSec    =
  548.                                     GetPlayRate(&b1VoiceData);
  549.                                 _WaveHeader.nAvgBytesPerSec =
  550.                                     _WaveHeader.nSamplesPerSec<<UserStereoMono;
  551.  
  552.                                 _WaveHeader.nChannels    = UserStereoMono+1;
  553.                                 _WaveHeader.nBlockAlign = UserStereoMono+1;
  554.  
  555.                         /* get the size of the data portion                     */
  556.  
  557.                             ptr = (long*) &b1VoiceData.bsize[0];
  558.                             SampleSize = (*ptr & 0x00ffffff) - 2;
  559.                             break;
  560.  
  561.                     case TERMINATOR:
  562.                         printf ("Terminator encountered - No sample data in the file!\n");
  563.                         DoExit(0);
  564.  
  565.                     case VOICECONTINUE:
  566.                         printf ("VOICECONTINUE - Not supported as the 1st record\n");
  567.                         DoExit(0);
  568.  
  569.                     case SILENCE:
  570.  
  571.                         /* fill out the rest of the header                        */
  572.  
  573.                             for (n=0;n<(sizeof(bSILENCE)-(sizeof(bVOCDATAHDR)));n++)
  574.                                  *b++ = getc(inf);
  575.  
  576.                             SampleSize = LONG (((bSILENCE*)&b1VoiceData)->period);
  577.                             break;
  578.  
  579.                     case MARKER:
  580.                         printf ("MARKER - Currently an Unsupported header entry!\n");
  581.                         DoExit(0);
  582.  
  583.                     case ASCIITEXT:
  584.                         printf ("ASCIITEXT - Currently an Unsupported header entry!\n");
  585.                         DoExit(0);
  586.  
  587.                     case REPEAT:
  588.                         printf ("REPEAT - Currently an Unsupported header entry!\n");
  589.                         DoExit(0);
  590.  
  591.                     case ENDREPEAT:
  592.                         printf ("ENDREPEAT - Currently an Unsupported header entry!\n");
  593.                         DoExit(0);
  594.  
  595.                     default:
  596.                         printf ("\aUnknown record type encountered in .VOC file!\n");
  597.                         DoExit(0);
  598.                 }
  599.         }
  600.  
  601.         if (FileType == SOU_FORMAT) {
  602.  
  603.                 if (UserSampleRate != -1)
  604.                     c = UserStereoMono;
  605.                 else {
  606.                     while (1) {
  607.                         printf ("\nEnter (1) for mono, (2) for stereo: ");
  608.                         c = getkey();
  609.                         c -= 0x31;
  610.                         if (!((c < 0) || (c > 1)))
  611.                             break;
  612.                     }
  613.                     UserStereoMono = c;
  614.                 }
  615.  
  616.                 _WaveHeader.nSamplesPerSec  =
  617.                     GetPlayRate(&b1VoiceData);
  618.                 _WaveHeader.nAvgBytesPerSec =
  619.                     _WaveHeader.nSamplesPerSec << UserStereoMono;
  620.  
  621.                 _WaveHeader.nChannels    = UserStereoMono+1;
  622.                 _WaveHeader.nBlockAlign = UserStereoMono+1;
  623.         }
  624.  
  625.     /* with the new header data, write it out to the new file            */
  626.  
  627.         putc ('R',ouf);                /* riff header                  */
  628.         putc ('I',ouf);
  629.         putc ('F',ouf);
  630.         putc ('F',ouf);
  631.  
  632.         fgetpos (ouf,&riffpos);
  633.  
  634.         putc (0x00,ouf);               /* riff length                   */
  635.         putc (0x00,ouf);
  636.         putc (0x00,ouf);
  637.         putc (0x00,ouf);
  638.  
  639.         putc ('W',ouf);                /* wave header                  */
  640.         putc ('A',ouf);
  641.         putc ('V',ouf);
  642.         putc ('E',ouf);
  643.  
  644.         putc ('f',ouf);                /* wave fmt block               */
  645.         putc ('m',ouf);
  646.         putc ('t',ouf);
  647.         putc (' ',ouf);
  648.  
  649.         putc (0x10,ouf);               /* wave fmt block length        */
  650.         putc (0x00,ouf);
  651.         putc (0x00,ouf);
  652.         putc (0x00,ouf);
  653.  
  654.         /* handle 16 bit PCM changes to the header                       */
  655.  
  656.         _WaveHeader.nBitsPerSample = PCMSize;
  657.         if (PCMSize == 16)
  658.             _WaveHeader.nAvgBytesPerSec <<= 1;
  659.  
  660.         b = (char *) &_WaveHeader;     /* wave data structure          */
  661.  
  662.         for (n=0;n<(sizeof(WaveInfo));n++)
  663.             putc (*b++,ouf);
  664.  
  665.         putc ('d',ouf);                /* data header                  */
  666.         putc ('a',ouf);
  667.         putc ('t',ouf);
  668.         putc ('a',ouf);
  669.  
  670.         fgetpos (ouf,&datapos);
  671.  
  672.         putc (0x00,ouf);               /* data length                   */
  673.         putc (0x00,ouf);
  674.         putc (0x00,ouf);
  675.         putc (0x00,ouf);
  676.  
  677. }
  678.  
  679.  
  680.     /*\
  681.     |*|----====< WriteckSize >====----
  682.     |*|
  683.     |*| write the header information on the .WAV file
  684.     |*|
  685.     \*/
  686. WriteckSize()
  687. {
  688. int n;
  689. char *s;
  690. long l;
  691.  
  692.     /* pad to a word boundary                                            */
  693.  
  694.         PadByte = FALSE;
  695.         if (((TotalSampleSize+44)&1)) {
  696.             PadByte = TRUE;
  697.             putc (lastsample,ouf);
  698.         }
  699.  
  700.         printf ("\ntotal sample size = %ld\n",TotalSampleSize);
  701.  
  702.     /* close the output file                                            */
  703.  
  704.         fclose (ouf);
  705.  
  706.         if ((ouf = fopen(TargetFile,"r+b")) == 0) {
  707.             printf ("\acannot re-open the output file to install data size:\"%s\" Try Again!\n");
  708.             DoExit (1);
  709.         }
  710.  
  711.     /* write the data length of the sampled sound                        */
  712.  
  713.         fsetpos (ouf,&datapos);
  714.         l = TotalSampleSize;
  715.         for (n=0;n<4;n++) { putc (((char)(l & 0xff)),ouf); l = l >> 8; }
  716.  
  717.     /* write the riff length of the sampled sound                        */
  718.  
  719.         fsetpos (ouf,&riffpos);
  720.         l = TotalSampleSize + 36;
  721.         if (PadByte) l++;
  722.         for (n=0;n<4;n++) { putc (((char)(l & 0xff)),ouf); l = l >> 8; }
  723.  
  724.         fclose (ouf);
  725. }
  726.  
  727.     /*\
  728.     |*| end of PLAY
  729.     \*/
  730.  
  731.  
  732.  
  733.  
  734.